AM Radio Project¶
Date: 2024-11-05
Name: Sama Patnaik
Partner's name: Marie Spencer
import numpy as np
import array
import pandas as pd
import matplotlib.pyplot as plt
import data_entry2
5th Nov 2024 ----------------------------------------------¶
Objectives/Briefing:¶
We will construct our AM radio over the span of 3 weeks, with updates given here every lab.
We will build 3 major parts of the circuit - the tank circuit, demodulator, and the amplifier.
To stay on track and ensure we finish on time (hopefully with enough to spare on debugging and trouble shooting), we will finish setting up the amplifier and the demodulator in week 1, then the tank circuit in week 2, and wrap up in week 3.
This is what the entire circuit will look like by week 3.
- Sketch/annotations:
Part 1¶
DMM measurements for part 1 (amplifier) with uncertainties¶
Amplifier:
- 0.01 μF -->
- 220 μF -->
- 1 MOhm -->
- R1 (Rg) (variable resistor -allows us to control the gain) --> 2.504 kOhm ±(2.504* 0.5% + 0.003) --> 2.504 kOhm ± 0.01552 kOhm
- R2 (Rf) (10 kOhm) --> 9.97 kOhm ±(9.97* 0.5% + 0.03) --> 9.97 kOhm ± 0.07985 kOhm
- We will measure the components 1, 2, and 3 later when we try to connect the demodulator and the amplifier together.
Notes¶
We will test the amplifier by supplying an input voltage which would be a sine function from the function generator -- starting at 1 kHz, and amplitude of 200mV (no offset). First we will test the amplifier without the 0.01 μF
We have the input on CH1 and the output on CH2 with DC coupling on. Vin is our function generator and Vout is the oscilloscope. We have our BNC tee on the function generator to connect the two channels together on the circuit and the oscilloscope.
We will measure the range of amplitudes Vin and Vout on a data table which will give us undistorted signals on the oscilloscope and also make a plot of Vin vs Vout to determine the gain which would be the slope.
We will include screenshots/photos of the circuit and oscilloscope if needed.
Screenshots/photos:¶
Without capacitor:
With capacitor:
Calculating gain and plots of gain (Vin vs Vout)¶
# calculating gain:
Rf = 9.97
uRf = 0.07985
Rg = 2.504
uRg = 0.01552
gain = 1 + Rf/Rg
ugain = gain* np.sqrt((uRf/Rf)**2 + (uRg/Rg)**2)
print("This is the calculated gain: ", f"{gain: .3g}", " ± ", f"{ugain: .3g}")
This is the calculated gain: 4.98 ± 0.0505
- At 1.4 Vpp, we noticed a slight distortion in the sine wave when playing around with the oscilloscope
de = data_entry2.sheet("projectpt1_data.csv")
Sheet name: projectpt1_data.csv
# The script below fits to a sine wave, but can be modified for other functions
# First, we load some python packages
import matplotlib.pyplot as plt
import numpy as np
from scipy.optimize import curve_fit
################################################
# LIST OF ALL INPUTS
################################################
# fname is assumed to be in a four-column .csv file (comma separated values). The first two rows are
# assumed to be headers, like those produced in our code for packing oscilloscope data.
# The four columns are x-values, x-uncertainties, y-values, y-uncertainties.
# The .csv file must be in the same
# folder as this fit program, otherwise the full file extension must be added
# to fname: e.g. fname = 'folder/subfolder/subsubfolder/file.csv'
fname = "projectpt1_data.csv"
x_name = "Ampout"
x_units = "V"
y_name = "Ampin"
y_units = "V"
# The model you will fit to is defined below, in this case a sine wave.
# The parameters in the model are amplitude, freqency, and phase.
# To get a least squares fitting process started, it is necessary to provide good
# initial guesses for the parameters. From your plots of the data so far, you can make good guesses at these parameters.
param_names = ["slope"]
# definition of the fit function
# def fit_function(x, amplitude,tau):
# fit function is a linear model with slope and intercept
def fit_function(x, slope):
return x*slope
# load the file "fname", defined above# load the file "fname", defined above;
# if you have file with more than 4 columns, you may need to select different indicies for "usecols" (starting counting at 0)
data = np.loadtxt(fname, delimiter=",", comments="#", usecols=(0, 1, 2, 3), skiprows=2)
################################################
# READ IN DATA COLUMNS
################################################
# Here is where you access the data columns.
# You may need to alter these to choose what is on the y-axis and what is on the x-axis.
x = AmpinVec[0:9]
y = AmpoutVec[0:9]
y_sigma = uampoutVec[0:9]
# calculate the best fit slope analytically (1-parameter solution)
m = sum(x*y/y_sigma**2)/sum((x/y_sigma)**2)
# calculate uncertainty of the best fit slope
m_sigma = np.sqrt(1/sum((x/y_sigma)**2))
print ("Slope is", m, "+/-", m_sigma)
###############################################################################
# calculates and prints the chi-squared, degrees of freedon, and weighted chi-squared
###############################################################################
# function that calculates the chi square value of a fit
def chi_square (param1, x, y, sigma):
#
return np.sum((y-fit_function(x, param1))**2/sigma**2)
# calculate and print chi square as well as the per degree-of-freedom value
chi2 = chi_square(m,x,y,y_sigma)
# degrees of freedom is the number of data points minus the number of parameters
dof = len(x) - 1
print ("\nGoodness of fit - Chi-squared measure:")
print ("degrees of freedom = {}, Chi2/dof = {}\n".format(dof, chi2/dof))
# residual is the difference between the data and model
x_fitfunc = np.linspace(min(x), max(x), 500)
y_fitfunc = fit_function(x_fitfunc, m)
y_fit = fit_function(x, m)
residual = y-y_fit
# creates a histogram of the residuals
hist,bins = np.histogram(residual,bins=30)
fig = plt.figure(figsize=(7,15))
ax1 = fig.add_subplot(311)
ax1.errorbar(x,y,yerr=y_sigma,marker='.',linestyle='',label="measured data")
ax1.plot(x_fitfunc,y_fitfunc,marker="",linestyle="-",linewidth=2,color="r",
label=" fit")
# add axis labels and title
ax1.set_xlabel('{} [{}]'.format(x_name,x_units))
ax1.set_ylabel('{} [{}]'.format(y_name,y_units))
ax1.set_title('Best fit of 1-Parameter Linear Model')
# set the x and y boundaries of your plot
#plt.xlim(lower_x,upper_x)
#plt.ylim(lower_y,upper_y)
# show a legend. loc='best' places legend where least amount of data is
# obstructed.
ax1.legend(loc='best',numpoints=1)
# this code produces a figure with a plot of the residuals as well
# as a histogram of the residuals.
# fig = plt.figure(figsize=(7,10))
ax2 = fig.add_subplot(312)
ax2.errorbar(x,residual,yerr=y_sigma,marker='.',linestyle='',
label="residual (y-y_fit)")
ax2.hlines(0,np.min(x),np.max(x),lw=2,alpha=0.8)
ax2.set_xlabel('{} [{}]'.format(x_name,x_units))
ax2.set_ylabel('y-y_fit [{}]'.format(y_units))
ax2.set_title('Residuals for the Best Fit')
ax2.legend(loc='best',numpoints=1)
ax3 = fig.add_subplot(313)
ax3.bar(bins[:-1],hist,width=bins[1]-bins[0])
ax3.set_ylim(0,1.2*np.max(hist))
ax3.set_xlabel('y-y_fit [{}]'.format(y_units))
ax3.set_ylabel('Number of occurences')
ax3.set_title('Histogram of the Residuals')
"""
Modify the following lines to change the name of the file used to store a JPEG of your best fit graphs
"""
# Before showing the plot, you can also save a copy of the figure as a JPEG.
# The order is important here because plt.show clears the plot information after displaying it.
plt.savefig('FittingResults.jpeg')
plt.show()
Slope is 4.876822037428694 +/- 0.02051038260565326 Goodness of fit - Chi-squared measure: degrees of freedom = 8, Chi2/dof = 4.450738263338465
Analysis of the plot above: ----- 19th Nov 2024¶
- The slope of 4.87 from the model matches what we calculated so that is good.
- We have a chi-squared of around 4 but i believe this is because of the one data point to the right where we can see that at the very large Ampout value, we see the gain roll off (roll off point). Other than that, it is a very linear relationship and the data fits the model well
- We can also see that most of the error bars pass through the middle line, and are evenly spread above and below the line, again indicating that our data is a good fit to the linear model. The outlier again is due to the right most data point where we see the gain fall off.
- Now we are going to keep the amplitude constant - at 200mVpp - this is to test the independence of the gain from the frequency.
- We are jumping to higher frequency on row 4 because we wanted to be efficient on time and ensure we actually see a roll off point on the oscilloscope
27th Nov 2024:
- Reporting the parameters from the model:
- We have our slope which is our gain value reported to approximately 4.88 +/- 0.0205, again this matches up with what we calculated above.
defreq = data_entry2.sheet("projectpt1freq_data.csv")
Sheet name: projectpt1freq_data.csv
plotting gain vs frequency - Nov 18th, 2024¶
# import the library numpy and rename it np
import numpy as np
import array
# import the library matplotlib and rename it plot
import matplotlib.pyplot as plt
#name the input file with the data
fname = 'projectpt1freq_data.csv'
# This block reads in data - the file is assumed to be in csv format (comma separated variables).
# Files need to be specified with a full path OR they have to be saved in the same folder as the script
#
data = np.loadtxt(fname, delimiter=',', comments='#',usecols=(0,1,2,3),skiprows=2)
# generate an array which is the first column of data. Note the first column is
# indexed as zero.
x = freqVec
# generate an array for the x uncertainty (column index 1)
x_sigma = uvinVec
# generate an array for the y values (column index 2)
y = VoutVec/VinVec
# generate an array for y uncertainty (column index 3)
y_sigma = uvoutVec
# This block creates a plot
plt.errorbar(x,y,marker='.',linestyle='',label="measured data")
plt.xlabel(' Frequency (Hz) ')
plt.ylabel(' Gain ')
plt.title(' Gain vs frequency ')
plt.show()
- From the plot above we can see frequency dependence, we can see that there is a region from 0Hz to 200Hz where we have a somewhat stable and linear relationship between the gain and the frequency, but after 300 Hz we see a roll off -- so basically as frequency increases, the gain decreases.
we find that at 400kHz the amplitude decreases quite a lot so I believe this is the roll off point
the two data points that overly on top of the data points around 4.9 seem like outliers and and once we do that we can see the linear relationship.
Working with the offset¶
- Now we will add the 0.01 μF at the input to the amplifier and repeat the above steps to see how the Vout signal from the OpAmp changes in response to a DC offset
- Both CH1 and CH2 are DC coupled.
- We will add screenshots of the oscilloscope images on this behaviour
- We set the frequency back to 1kHz
- We found 780mV to be the offset where we have distortion on the sine wave.
Nov 26th 2024 - adding the images:
It is not very clear, but there is distortion on the sine wave in the second picture when we have 780mV
Notes on amplifier debugging, and more: -- 26th Nov 2024¶
- Initially we had issues with the amplifier where we messed up the connections between the resistors and ground but we figured it out after debugging and tracing through. For some time, we also were having trouble seeing any sort of signal on the oscilloscope, but after playing around more we were able to figure out the trigger settings on the oscilloscope.
Part 2¶
DMM measurements for part 2 (demodulator) with uncertainties¶
Demodulator:
- Ge diode --> 0.3V ** just to confirm that we are using a Ge diode rather than a silicon one
- 0.5 nF --> 0.438 nF ± (5.0%*0.438 + 0.02) --> 0.438 nF ± 0.0419
- 100 kOhm --> 98.3 kOhm ± (0.5%*98.3 + 0.3)--> 98.3 kOhm ± 0.7915
Notes:¶
- Adding onto our amplifier circuit from above, here is the circuit image of the demodulator (the black ring on the diode is on the right side)
- We have ModWave to be on sine, ModFreq to 6.9kHz and the amplitude to 0.5V on the function generator
- We are going to leave space to add the 1 MOhm and the 0.01 μF (I will add the DMM measurements for these components back up)
- The Ge diode will rectify the AM signal so there is only positive voltages (which is why we see the curve above the axis on the scope) and the resistor and the capacitor acts as the low pass filter which removes the carrier frequency.
Measurements on amplitude, offset and frequency on CH1 and CH2¶
- Using the cursors we will measure these values on the oscilloscope
- We are measuring the amplitude and frequency of the amplitude modulation in the input signal (CH1)
- We set the oscilloscope on RUN/STOP to actually be able to measure both CH1 and CH2
- We are also measuring the amplitude, frequency and offset on the output signal (CH2), then we will compare input measurements with the output measurements
--> amplitude of CH1: 0.508mV +/- 0.012mV
--> frequency of CH1: 146.6μs +/- 1μs
--> amplitude of CH2: 74mV +/- 5mV
--> frequency of CH2: 146μs +/- 1μs
--> offset of CH2: 20mV +/- 4mV
Nov 18th, 2024 edits continued:¶
add images of the demodulator circuit along with the oscilloscope
1st pair of oscillscope imgs:
2nd pair of oscilloscope imgs:
Adding some more images on 26th Nov 2024:
Unfiltered:
Filtered:
Notes on the demodulator, debugging, and more: -- 26th Nov 2024¶
- The germanium Ge diode acts as the rectifier which is then followed by the low pass filter so the images above show a comparison before applying just the rectifier and then having both the rectified and filtered wave.
- Something that we were struggling with was a lot of noise on the oscilloscope which we fixed by playing around with the circuit more, and then we realized one of our connections on the circuit was incorrect (the connections for the capacitor and the resistor were messed up)
- We were also struggling to have the CH1 signal to stop flickering and we realized it was because it needed to be triggered.
Part 3¶
LC (Tank) Circuit - Nov 19th 2024 --------------------------------------¶
In this part of the circuit, the tank circuit behaves like a narrow bandpass filter and only lets a signal pass through if the resonant frequency is tuned close to the carrier frequency of 690 kHz.
Circuit:
- We have a test coil for which we can make a test signal using the frequency generator and the oscilloscope, and tweak around with the capacitance to see if it matches with our 690kHz frequency signal. We will have a coil with 10 turns tightly around the inductor, with one side connected to ground and the other connected to the 100kOhm resistor.
The signal we see at the amplifier output will become a maximum when LC circuit’s resonant frequency is tuned to match the 690 kHz
We will set the frequency to 690 kHz, amplitude to 0.5 V both on the function generator, and amplitude modulation at 6.9 kHz.
CH1 --> connected to the function generator and CH2 --> connected amplifier
set to a 100% depth on the function generator
We will also connect up the amplifier and the demodulator using the 1Mohm resistor and the 0.01 μF capacitor with the DMM measurements below
We will add images of the circuit, the function generator, and oscilloscope:
images of the signal on resonance and well off resonance -- max amplitude.
- Describe what is observed as you vary the capacitance slowly through the resonance When we vary the capacitance slowly through the resonance, we see the amplitude changing, and eventually we reached the maximum output amplitude.
we have set up the tank circuit like the above circuit image shows so that we have enough space for the antenna, 1MOhm resistor, 0.01 μF capacitor, 220 μF to be near the speaker
DMM measurements with uncertainties for 471 μH inductor and 24-240 pF variable capacitor¶
- inductor: 409 microH
- variable capacitor to get max amplitude: 0.084 nF ±(2.0% * 0.084 + 0.005) --> 0.084 nF ± 0.00668
- 100 Ohm resistor: 99.09 Ohm ± (2.0% * 99.09 + 0.05) --> 99.09 Ohm ± 2.0318
- 1Mohm resistor: 1.003 MOhms ± (2.0% * 1.003 + 0.005) --> 1.003 MOhms ± 0.02506
- 0.01 μF capacitor: 10.77 nF ± (2.0% * 10.77 + 0.05) --> 10.77 nF ± 0.2654
We will use this equation to calculate the capacitance we should set on our variable capacitor:
f_0 = 1/(2pisqrt(LC))
Uncertainties above come from the Aneng digital uncertainty guide
#calculating the capacitance
import numpy as np
import array
# f_0 = 1/ (2 * np.pi * sqrt(L*C))
f_0 = 690*1000
L = 471 * 10**-6
C = 1/(2*np.pi*(L)**(1/2)*f_0)**2
print("this is our capacitance value using nominal values in the instructions: ", f"{C: .4g}", "F")
this is our capacitance value using nominal values in the instructions: 1.13e-10 F
Vout vs Vin¶
- Here we will plot Vout and Vin to get the peak near 690 kHz
- The uncertainties come from using the cursors on the oscilloscope
- The uncertainty on the frequency comes from the frequency generator
dataLC = data_entry2.sheet("projectLC_data.csv")
Sheet name: projectLC_data.csv
#Vout vs Vin
# import the library numpy and rename it np
import numpy as np
import array
# import the library matplotlib and rename it plot
import matplotlib.pyplot as plt
#name the input file with the data
fname = 'projectLC_data.csv'
# This block reads in data - the file is assumed to be in csv format (comma separated variables).
# Files need to be specified with a full path OR they have to be saved in the same folder as the script
#
data = np.loadtxt(fname, delimiter=',', comments='#',usecols=(0,1,2,3),skiprows=2)
# generate an array which is the first column of data. Note the first column is
# indexed as zero.
x = data[:,2]
# generate an array for the x uncertainty (column index 1)
x_sigma = data[:,3]
# generate an array for the y values (column index 2)
y = data[:,0]
# generate an array for y uncertainty (column index 3)
y_sigma = data[:,1]
# This block creates a plot
plt.errorbar(x,y,xerr=x_sigma,yerr=y_sigma,marker='.',linestyle='',label="measured data")
plt.xscale("log")
plt.xlabel('frequency')
plt.ylabel('Voltage')
plt.title('LRC response')
plt.show()
Fitting the LC data:¶
#calculating initial parameters
RL = 0.85 #ohms
uRL = 0.01*0.85 + 0.03 #ohms
C = 0.084 * 10**-9 #F --> this was measured with the DMM after tuning the circuit
uC = (0.05*0.084 + 0.02)*10**-9 #nF
L = 409 * 10**-6 #H +/- 5% + 0.000001
uL = (L * 0.05) + 0.000001
F0 = 690000 #Hz
gamma = RL/L
ugamma = gamma* np.sqrt((uRL/RL)**2 + (uC/C)**2)
print("calculated gamma = ", f"{gamma: .7g}", "+/- ",f"{ugamma: .3g}", "Ohms/H")
calculated gamma = 2078.24 +/- 606 Ohms/H
# Load python packages
import matplotlib.pyplot as plt
import numpy as np
from scipy.optimize import curve_fit
###############################################################################
# DEFINED FITTING FUNCTIONS
###############################################################################
def sine_func(x, amplitude, freq, phase):
return amplitude * np.sin(2.0 * np.pi * freq * x + phase)
def offset_sine_func(x, amplitude, freq, phase, offset):
return (amplitude * np.sin(2.0 * np.pi * freq * x + phase)) + offset
def exponential_func(x, amplitude, tau, voffset):
return amplitude * np.exp(x/(-1.0*tau)) + voffset
def ringdown_function(x, amplitude, tau, resonantf, phase):
return amplitude * np.exp(-x/tau) * np.cos(2.0*np.pi * resonantf * x + phase)
def linear_func(x, slope, intercept):
return slope * x + intercept
def RCresp_func(x, tau, V0, voffset):
return V0/np.sqrt(1+(2*np.pi*tau*x)**2) + voffset
def LRCresp_func(x, f0, Vin, gamma):
return Vin/(np.sqrt(1+(2*np.pi/(gamma*x))**2*(x**2-f0**2)**2))
###############################################################################
# LIST OF ALL INPUTS
###############################################################################
# Name of the data file
fname = "projectLC_data.csv"
# Names and units of data columns from fname
x_name = "frequency"
x_units = "Hz"
y_name = "Voltage"
y_units = "mV"
# Modify to change the fitting function, parameter names and to set initial parameter guesses
fit_function = LRCresp_func
param_names = ("f0", "Vin", "gamma")
guesses = (690,0.5, 2078.24)
# Flags for optional features
show_covariance_matrix = False
set_xy_boundaries = False
lower_x = -0.01 # these values ignored if set_xy_boundaries = False
upper_x = 0.01
lower_y = -1
upper_y = 1
###############################################################################
# LOAD DATA
###############################################################################
# load the file fname and skip the first 'skiprows' rows
data = np.loadtxt(fname, delimiter=",", comments="#", usecols=(0, 1, 2, 3), skiprows=8)
# Assign the data file columns to variables for later use
x = data[:, 2]
y = data[:, 0]
y_sigma = data[:, 1]
###############################################################################
# INITIAL PLOT OF THE DATA
###############################################################################
# Define 500 points spanning the range of the x-data; for plotting smooth curves
xtheory = np.linspace(min(x), max(x), 500)
# Compare the guessed curve to the data for visual reference
y_guess = fit_function(xtheory, *guesses)
plt.errorbar(x, y, yerr=y_sigma, marker=".", linestyle="", label="Measured data")
plt.plot(
xtheory,
y_guess,
marker="",
linestyle="-",
linewidth=1,
color="g",
label="Initial parameter guesses",
)
plt.xlabel(f"{x_name} [{x_units}]")
plt.ylabel(f"{y_name} [{y_units}]")
plt.title(r"Comparison between the data and the intial parameter guesses")
plt.legend(loc="best", numpoints=1)
plt.show()
# calculate the value of the model at each of the x-values of the data set
y_fit = fit_function(x, *guesses)
# Residuals are the difference between the data and theory
residual = y - y_fit
# Plot the residuals
plt.errorbar(x, residual, yerr=y_sigma, marker=".", linestyle="", label="residuals")
plt.xlabel(f"{x_name} [{x_units}]")
plt.ylabel(f"Residual y-y_fit [{y_units}]")
plt.title("Residuals using initial parameter guesses")
plt.show()
###############################################################################
# PERFORM THE FIT AND PRINT RESULTS
###############################################################################
# Use curve_fit to perform the fit
# fit_function: defined above to choose a specific fitting function
# fit_params: holds the resulting fit parameters
# fit_cov: the covariance matrix between all the parameters
# (used to extract fitting parameter uncertanties)
# maxfev=10**5: maximum number of fitting procedure iterations before giving up
# absolute_sigma=True: uncertainties are treated as absolute (not relative)
fit_params, fit_cov = curve_fit(
fit_function, x, y, sigma=y_sigma,
p0=guesses,absolute_sigma=True, maxfev=10**5)
# Define the function that calculates chi-squared
def chi_square(fit_parameters, x, y, sigma):
dof = len(x) - len(fit_params)
return np.sum((y - fit_function(x, *fit_parameters)) ** 2 / sigma**2)/dof
# Calculate and print reduced chi-squared
chi2 = chi_square(fit_params, x, y, y_sigma)
print("Chi-squared = ", chi2)
# Calculate the uncertainties in the fit parameters
fit_params_error = np.sqrt(np.diag(fit_cov))
# Print the fit parameters with uncertianties
print("\nFit parameters:")
for i in range(len(fit_params)):
print(f" {param_names[i]} = {fit_params[i]:.3e} ± {fit_params_error[i]:.3e}")
print("\n")
# (Optional) Print the covariance between all variables
if show_covariance_matrix:
print("Covariance between fit parameters:")
for i, fit_covariance in enumerate(fit_cov):
for j in range(i+1,len(fit_covariance)):
print(f" {param_names[i]} and {param_names[j]}: {fit_cov[i,j]:.3e}")
print("\n")
# residual is the difference between the data and model
x_fitfunc = np.linspace(min(x), max(x), 500)
y_fitfunc = fit_function(x_fitfunc, *fit_params)
y_fit = fit_function(x, *fit_params)
residual = y-y_fit
###############################################################################
# PRODUCE A MULTIPANEL PLOT, WITH SCATTER PLOT, RESIDUALS AND RESIDUALS HISTOGRAM
###############################################################################
# The size of the canvas
fig = plt.figure(figsize=(7,15))
# The scatter plot
ax1 = fig.add_subplot(311)
ax1.errorbar(x,y,yerr=y_sigma,marker='.',linestyle='',label="Measured data")
ax1.plot(x_fitfunc, y_fitfunc, marker="", linestyle="-", linewidth=2,color="r", label="Fit")
ax1.set_xlabel(f"{x_name} [{x_units}]")
ax1.set_ylabel(f"{y_name} [{y_units}]")
ax1.set_title('Best Fit of Function to Data')
# (Optional) set the x and y boundaries of your plot
if set_xy_boundaries:
plt.xlim(lower_x,upper_x)
plt.ylim(lower_y,upper_y)
# Show the legend. loc='best' places it where the date are least obstructed
ax1.legend(loc='best',numpoints=1)
# The residuals plot
ax2 = fig.add_subplot(312)
ax2.errorbar(x, residual, yerr=y_sigma,marker='.', linestyle='', label="Residual (y-y_fit)")
ax2.hlines(0,np.min(x),np.max(x),lw=2,alpha=0.8)
ax2.set_xlabel(f"{x_name} [{x_units}]")
ax2.set_ylabel(f"y-y_fit [{y_units}]")
ax2.set_title('Residuals for the Best Fit')
ax2.legend(loc='best',numpoints=1)
# Histogram of the residuals
ax3 = fig.add_subplot(313)
hist,bins = np.histogram(residual,bins=30)
ax3.bar(bins[:-1],hist,width=bins[1]-bins[0])
ax3.set_ylim(0,1.2*np.max(hist))
ax3.set_xlabel(f"y-y_fit [{y_units}]")
ax3.set_ylabel('Number of occurences')
ax3.set_title('Histogram of the Residuals')
# Save a copy of the figure as a png
plt.savefig('FittingResults.png')
# Show the plot
plt.show()
Chi-squared = 370.25264042759517 Fit parameters: f0 = 6.755e+02 ± 2.330e-01 Vin = 1.948e+00 ± 1.291e-02 gamma = 1.972e+02 ± 3.249e+00
27th Nov 2024 -- just an update¶
comparing the effective resistance of the circuit using the gamma value from the model and the expected resistance from inductor of 0.85 ohms:
- We should get a small effective resistance value:
gamma_model = 197.2 #± 3.249
gamma_calc = 2078.24
R_model = gamma_model * L
print("this is the effective resistance from circuit: ", f"{R_model: .3g}", "Ohms")
this is the effective resistance from circuit: 0.0807 Ohms
We can see that this is quite small, this means our circuit has a small effective resistance.
26th November 2024 ---------------------------------------------------¶
Analysis of the plots above from LRC tank circuit:
- Our chi-squared is quite high (around 370) which I think is to do with the uncertainty. And I think we could have taken more data given more time to see if we could get a better fit.
- The residuals plot and the histogram both show that the model is not really fitting the data well, but I think it is because the curve is asymmetrical so maybe adding an offset, or chopping off the right tail would make it better. But I don't think it is necessary to do that because the data above shows the true LRC curve.
- Reporting the parameters from the fit above: We have frequency at 675.5 ± 0.233 kHz, input voltage at 1.948 ± 0.0129V, and gamma at 197.2 ± 3.25, these values are kind of off from the values we calculated and I am assuming it is because of the model is not fitting the data well enough.
Testing the AM radio¶
- We will test our AM radio while having the CH2 on and triggering from the scope on CH2, and connect the antenna like so (only added for the connection, everything else in our circuit is the same as before). We will tune the capacitor and the resistor so we can get the maximum amplitude on the oscillator, and then also tune it so that we get little/no noise. We will add image of the circuit with the speaker and the antenna connections below too:
Final Circuit:
Max amplitude signal:
Min amplitude signal:
Notes on the final circuit, debugging and more:¶
- We heard the radio on the speakers! Very cool :)
- Our amplifier had clipping on the screenshots above which is a flaw to the circuit which comes from the op-amp's limitations. A screen shot of this was also included above in the amplifier section of the report above (part 1).
- In terms of the biggest pitfalls of the circuit, I think what could have been improved was that we could have used a bigger breadboard to allow for more room considering how many components there are. I also think that to tested the circuit using the amplifier took a lot of time - I think there was a way to set up the frequency generator to test the breadboard which would have been more efficient and quicker.
- I think the way we would ensure the debugging process was smoother if we were to remake this circuit or a more complex circuit, would be to follow through and break the circuit into chunks (isolate each part of the circuit), and manually following through with the wire connections, comparing with a proper correct circuit diagram - I think that was the most helpful. I think this debugging process was something that needed to be practiced and the AM radio gave us a way to do that, which is amazing.